package com.qh.pay.controller;

import java.util.*;

import javax.servlet.http.HttpServletRequest;

import com.qh.common.dao.ProvinceDao;
import com.qh.common.service.impl.LocationServiceImpl;
import com.qh.pay.api.constenum.*;
import com.qh.pay.api.utils.*;
import com.qh.pay.exrick.common.utils.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.qh.common.config.Constant;
import com.qh.common.controller.BaseController;
import com.qh.common.domain.UserBankDO;
import com.qh.common.service.LocationService;
import com.qh.common.service.UserBankService;
import com.qh.common.utils.R;
import com.qh.common.utils.ShiroUtils;
import com.qh.pay.api.Order;
import com.qh.pay.api.PayConstants;
import com.qh.pay.domain.Agent;
import com.qh.pay.domain.Merchant;
import com.qh.pay.domain.PayAcctBal;
import com.qh.pay.service.AgentService;
import com.qh.pay.service.MerchantService;
import com.qh.pay.service.PayService;
import com.qh.redis.service.RedisUtil;
import com.qh.system.domain.UserDO;
import sun.management.resources.agent;

/**
 * @version 1.0.0
 * @ClassName PayController
 * @Description pay
 * @Date 2017年10月24日 上午11:30:22
 */
@RestController
@RequestMapping("/pay")
public class PayController extends BaseController {

    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(PayController.class);
    @Autowired
    private MerchantService merchantService;
    @Autowired
    private AgentService agentService;
    @Autowired
    private PayService payService;
    @Autowired
    private LocationService locationService;
    @Autowired
    private UserBankService userBankService;


    @GetMapping("/merchant/{merchNo}")
    public Merchant findByMerchNo(@PathVariable String merchNo) {
        return merchantService.get(merchNo);
    }


    /**
     * @param outChannel
     * @param accountNo
     * @return
     * @Description 扫码通道充值后台通知
     */
    @PostMapping("/notify")
    @ResponseBody
    public JSONObject notifyPayQr(String outChannel,
                                  String accountNo,
                                  String amount,
                                  String msg, HttpServletRequest request) {
        JSONObject jsonObject = RequestUtils.getJsonResultStream(request);
        logger.info("扫码通道充值后台通知：{},{},{}", outChannel, accountNo, amount);
        //业务逻辑处理
//		payService.orderDataMsg( jsonObject.getString("outChannel"), jsonObject.getString("accountNo"),
//				jsonObject.getString("amount"), jsonObject.getString("msg"));
        return null;
    }

    /**
     * @param request
     * @return
     * @Description 支付下单
     */
    @PostMapping("/order")
    public Object order(HttpServletRequest request) {
        R r = commDataCheck(request);
        if (R.ifSucc(r)) {
            return payService.order((Merchant) r.get(Constant.param_merch),
					(JSONObject) r.get(Constant.param_jsonData));
        } else {
            return r;
        }
    }


    /**
     * @return
     * @Description 可用金额
     */
    @PostMapping("/order/channal")
    public Object channal(HttpServletRequest request) {
        R r = commDataCheck(request);
        if (R.ifSucc(r)) {
            return payService.outChannal((Merchant) r.get(Constant.param_merch),
					(JSONObject) r.get(Constant.param_jsonData));
        } else {
            return r;
        }
    }

    @PostMapping("/order/channal/php")
    public Object channalPHP(String sign, String context, String encryptType, String merchNo,HttpServletRequest request) {
        R r = commDataCheckBase64(sign, context, encryptType, merchNo,request);
//		R r =  commDataCheck(request);
        if (R.ifSucc(r)) {
            return payService.outChannal((Merchant) r.get(Constant.param_merch),
					(JSONObject) r.get(Constant.param_jsonData));
        } else {
            return r;
        }
    }

    /**
     * @return
     * @Description 支付下单
     */
    @PostMapping("/order/php")
    public Object orderPHP(String sign, String context, String encryptType, String merchNo,HttpServletRequest request) {
        R r = commDataCheckBase64(sign, context, encryptType, merchNo,request);
        if (R.ifSucc(r)) {
            return payService.order((Merchant) r.get(Constant.param_merch),
					(JSONObject) r.get(Constant.param_jsonData));
        } else {
            return r;
        }
    }

    /**
     * @return
     * @Description 支付下单
     */
    @GetMapping("/order/success")
    public String success(Model model) {
        model.addAttribute(Constant.result_msg, "支付成功");
        return PayConstants.url_pay_success;
    }

    /**
     * @param request
     * @return
     * @Description 代付下单
     */
    @PostMapping("/order/acp")
    public Object orderAcp(HttpServletRequest request) {
        R r = commDataCheck(request);
        if (R.ifSucc(r)) {
            Merchant merchant = (Merchant) r.get(Constant.param_merch);
            return payService.orderAcp(merchant, (JSONObject) r.get(Constant.param_jsonData));
        } else {
            return r;
        }
    }

    /**
     * @return
     * @Description 支付查询
     */
    @PostMapping("/order/query/php")
    public Object query(HttpServletRequest request) {
        R r = commDataCheck(request);
        if (R.ifSucc(r)) {
            return payService.query((Merchant) r.get(Constant.param_merch),
					(JSONObject) r.get(Constant.param_jsonData));
        } else {
            return r;
        }
    }

    /**
     * @return
     * @Description 支付查询
     */
    @PostMapping("/order/queryPHP")
    public Object queryPHP(String sign, String context, String encryptType, String merchNo,HttpServletRequest request) {
        R r = commDataCheckBase64(sign, context, encryptType, merchNo,request);
        if (R.ifSucc(r)) {
            return payService.query((Merchant) r.get(Constant.param_merch),
					(JSONObject) r.get(Constant.param_jsonData));
        } else {
            return r;
        }
    }

    /**
     * @return
     * @Description 支付查询
     */
    @PostMapping("/order/test")
    public Object queryState(String order) {

        return R.ok("请求成功" + order);
    }

    /**
     * @return
     * @Description 支付查询
     */
    @PostMapping("/order/state")
    public Object queryState(String orderNo, String merchNo) {
        return payService.query(merchNo, orderNo);
    }

    /**
     * @param request
     * @return
     * @Description 代付查询
     */
    @PostMapping("/order/acp/query")
    public Object acpQuery(HttpServletRequest request) {
        R r = commDataCheck(request);
        if (R.ifSucc(r)) {
            return payService.acpQuery((Merchant) r.get(Constant.param_merch),
					(JSONObject) r.get(Constant.param_jsonData));
        } else {
            return r;
        }
    }

    /**
     * @param request
     * @return
     * @Description 通用检查方法
     */
    private R commDataCheck(HttpServletRequest request) {
        JSONObject jsonObject = RequestUtils.getJsonResultStream(request);
        if (jsonObject == null) {
            logger.info("获取请求参数失败");
            return R.error("请检查请求参数！");
        }
        String sign = jsonObject.getString("sign");
        logger.info("请求签名：{}", sign);
        if (ParamUtil.isEmpty(sign)) {
            logger.info("获取sign失败，参数为:" + jsonObject.toJSONString());
            return R.error("请检查签名参数！");
        }
        byte[] context = jsonObject.getBytes("context");
        if (ParamUtil.isEmpty(context)) {
            logger.info("获取context失败，参数为:" + jsonObject.toJSONString());
            return R.error("请检查加密内容！");
        }
        String merchNo = jsonObject.getString(OrderParamKey.merchNo.name());

        if (ParamUtil.isEmpty(merchNo)) {
            logger.error("商户号为空！" + merchNo);
            return R.error("商户号为空！" + merchNo);
        }

        Merchant merchant = merchantService.get(merchNo);
        if (merchant == null) {
            logger.error("商户不存在！" + merchNo);
            return R.error("商户不存在！" + merchNo);
        }
        if (!merchant.getStatus().equals(YesNoType.yes.id())) {
            logger.error("商户被禁用！" + merchNo);
            return R.error("商户异常！" + merchNo);
        }
//        if(!merchNo.equals("SH992255")||!merchNo.equals("SH322106")){
//            if(StringUtils.isBlank(merchant.getContactsQq())){
//                return R.error("请先添加IP白名单");
//            }
//            List list = Arrays.asList( merchant.getContactsQq().split(","));
//            if(list!=null&&list.contains(getIPAddress(request))){
//
//            }else{
//                logger.error("IP地址不在白名单内" + merchNo);
//                return R.error("IP地址不在白名单内");
//            }
//        }

        Agent agent = agentService.get(merchant.getParentAgent());
        if (agent == null || !agent.getStatus().equals(YesNoType.yes.id())) {
            logger.error("商户上级代理被禁用！" + merchNo);
            return R.error("商户异常!");
        } else {
            if (agent.getLevel().equals(AgentLevel.two.id())) {
                agent = agentService.get(agent.getParentAgent());
                if (agent == null || !agent.getStatus().equals(YesNoType.yes.id())) {
                    logger.error("商户上级一级代理被禁用！" + merchNo);
                    return R.error("商户异常!");
                }
            }
        }

        logger.info("请求加密结果：{}", jsonObject);
        try {
            JSONObject jo = null;
            String encryptType = jsonObject.getString("encryptType");
            if ("RSA".equals(encryptType)) {

                if (RSAUtil.verify(context, merchant.getPublicKey(), sign)) {
                    logger.info("验签成功！", merchant.getPublicKey());

                } else {
                    logger.error("验签失败！" + merchNo);
                    return R.error("验签失败！" + merchNo);
                }
                String privateKey = merchantService.getPrivateKey(merchNo);
                String source = new String(RSAUtil.decryptByPrivateKey(context, privateKey), "UTF-8");
                logger.info("解密结果！" + source);
                jo = JSON.parseObject(source);
                jo.put(OrderParamKey.encryptType.name(), encryptType);
            } else if ("MD5".equals(encryptType)) {

                Base64.Decoder decoder = Base64.getDecoder();
                String privateKey = merchantService.getPrivateKey(merchNo);
                String contexts = jsonObject.getString("context");
                if (Md5Util.verify(contexts, sign, privateKey, "UTF-8")) {
                    String source = new String(decoder.decode(contexts), "UTF-8");
                    jo = JSON.parseObject(source);
                    logger.info("验签成功！", merchant.getPublicKey());
                    jo.put(OrderParamKey.encryptType.name(), encryptType);
                } else {
                    logger.error("验签失败！" + merchNo);
                    return R.error("验签失败！" + merchNo);
                }
                //解密
//				String source = new String(context,"UTF-8");
//				logger.info("解密结果！" + source);
//				jo = JSON.parseObject(source);
//				String privateKey = merchantService.getPrivateKey(merchNo);
//				if(Md5Util.verify(source, sign, privateKey, "UTF-8")){
//					logger.info("验签成功！", merchant.getPublicKey());
//					jo.put(OrderParamKey.encryptType.name(),encryptType);
//				}else{
//					logger.error("验签失败！" + merchNo);
//					return R.error("验签失败！" + merchNo);
//				}

            } else {
                return R.error("加密方式错误");
            }

            return R.ok().put(Constant.param_merch, merchant).put(Constant.param_jsonData, jo);

        } catch (Exception e) {
            logger.info(e.getMessage(), e);
            return R.error("请求异常！" + e.getMessage());
        }
    }

    private R commDataCheckBase64(String sign, String context, String encryptType, String merchNo,HttpServletRequest request) {
        System.out.println(getIPAddress(request));
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("sign", sign);
        jsonObject.put("context", context);
        jsonObject.put("encryptType", encryptType);
        jsonObject.put("merchNo", merchNo);

        if (jsonObject.isEmpty()) {
            logger.info("获取请求参数失败");
            return R.error("请检查请求参数！");
        }
        Base64.Decoder decoder = Base64.getDecoder();
        sign = jsonObject.getString("sign");
        logger.info("请求签名：{}", sign);
        if (ParamUtil.isEmpty(sign)) {
            logger.info("获取sign失败，参数为:" + jsonObject.toJSONString());
            return R.error("请检查签名参数！");
        }
        context = jsonObject.getString("context");
        if (ParamUtil.isEmpty(context)) {
            logger.info("获取context失败，参数为:" + jsonObject.toJSONString());
            return R.error("请检查加密内容！");
        }
        merchNo = jsonObject.getString(OrderParamKey.merchNo.name());

        if (ParamUtil.isEmpty(merchNo)) {
            logger.error("商户号为空！" + merchNo);
            return R.error("商户号为空！" + merchNo);
        }

        Merchant merchant = merchantService.get(merchNo);
        if (merchant == null) {
            logger.error("商户不存在！" + merchNo);
            return R.error("商户不存在！" + merchNo);
        }
        if (!merchant.getStatus().equals(YesNoType.yes.id())) {
            logger.error("商户被禁用！" + merchNo);
            return R.error("商户异常！" + merchNo);
        }
//        if(!merchNo.equals("SH992255")||!merchNo.equals("SH322106")){
//            if(StringUtils.isBlank(merchant.getContactsQq())){
//                return R.error("请先添加IP白名单");
//            }
//            List list = Arrays.asList( merchant.getContactsQq().split(","));
//            if(list!=null&&list.contains(getIPAddress(request))){
//
//            }else{
//                logger.error("IP地址不在白名单内" + merchNo);
//                return R.error("IP地址不在白名单内");
//            }
//        }




        Agent agent = agentService.get(merchant.getParentAgent());
        if (agent == null || !agent.getStatus().equals(YesNoType.yes.id())) {
            logger.error("商户上级代理被禁用！" + merchNo);
            return R.error("商户异常!");
        } else {
            if (agent.getLevel().equals(AgentLevel.two.id())) {
                agent = agentService.get(agent.getParentAgent());
                if (agent == null || !agent.getStatus().equals(YesNoType.yes.id())) {
                    logger.error("商户上级一级代理被禁用！" + merchNo);
                    return R.error("商户异常!");
                }
            }
        }

        logger.info("请求加密结果：{}", jsonObject);
        try {
            JSONObject jo = null;
            encryptType = jsonObject.getString("encryptType");
            if ("RSA".equals(encryptType)) {
                return R.error("PHP暂不支持RSA！" + merchNo);
//				String contextTxt = new String(decoder.decode(context), "UTF-8");
//				if(RSAUtil.verify(context.getBytes(), merchant.getPublicKey(), sign)){
//					logger.info("验签成功！", merchant.getPublicKey());
//				}else{
//					logger.error("验签失败！" + merchNo);
//					return R.error("验签失败！" + merchNo);
//				}
//				String privateKey = merchantService.getPrivateKey(merchNo);
//				String source  = new String(RSAUtil.decryptByPrivateKey(context.getBytes(),privateKey),"UTF-8");
//				logger.info("解密结果！" + source);
//				jo = JSON.parseObject(source);
//				jo.put(OrderParamKey.encryptType.name(),encryptType);
            } else if ("MD5".equals(encryptType)) {
                //解密

//				String source = new String(context,"UTF-8");


                String privateKey = merchantService.getPrivateKey(merchNo);
                if (Md5Util.verify(context, sign, privateKey, "UTF-8")) {
                    String source = new String(decoder.decode(context), "UTF-8");
                    jo = JSON.parseObject(source);
                    logger.info("验签成功！", merchant.getPublicKey());
                    jo.put(OrderParamKey.encryptType.name(), encryptType);
                } else {
                    logger.error("验签失败！" + merchNo);
                    return R.error("验签失败！" + merchNo);
                }

            } else {
                return R.error("加密方式错误");
            }

            return R.ok().put(Constant.param_merch, merchant).put(Constant.param_jsonData, jo);

        } catch (Exception e) {
            logger.info(e.getMessage(), e);
            return R.error("请求异常！" + e.getMessage());
        }
    }
    public static String getIPAddress(HttpServletRequest request) {
        String ip = null;

        //X-Forwarded-For：Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //Proxy-Client-IP：apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //WL-Proxy-Client-IP：weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //HTTP_CLIENT_IP：有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //X-Real-IP：nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        //有些网络通过多层代理，那么获取到的ip就会有多个，一般都是通过逗号（,）分割开来，并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }

        //还是不能获取到，最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
    /**
     * @param outChannel
     * @param merchNo
     * @param orderNo
     * @param businessNo
     * @return
     * @Description 同步订单信息
     */
    @GetMapping("/syncOrder/{outChannel}/{merchNo}/{orderNo}")
    @RequiresPermissions("pay:syncOrder")
    public Object syncOrder(@PathVariable("outChannel") String outChannel, @PathVariable("merchNo") String merchNo,
                            @PathVariable("orderNo") String orderNo, @RequestParam(required = false, name =
			"businessNo") String businessNo) {
        if (ParamUtil.isEmpty(outChannel)) {
            return R.error("渠道编码不能为空！");
        }
        if (OutChannel.jfDesc().containsKey(outChannel) && ParamUtil.isEmpty(businessNo)) {
            return R.error("业务单号不能为空！");
        }
        if (ParamUtil.isEmpty(merchNo) || ParamUtil.isEmpty(orderNo)) {
            return R.error("参数不能为空！");
        }
        return payService.syncOrder(merchNo, orderNo, businessNo);
    }

    /**
     * @param outChannel
     * @param merchNo
     * @param orderNo
     * @param businessNo
     * @return
     * @Description 同步代付订单信息
     */
    @GetMapping("/syncOrderAcp/{outChannel}/{merchNo}/{orderNo}")
    @RequiresPermissions("pay:syncOrderAcp")
    public Object syncOrderAcp(@PathVariable("outChannel") String outChannel, @PathVariable("merchNo") String merchNo,
                               @PathVariable("orderNo") String orderNo, @RequestParam(required = false, name =
			"businessNo") String businessNo) {
        if (ParamUtil.isEmpty(outChannel)) {
            return R.error("渠道编码不能为空！");
        }
        if (OutChannel.jfDesc().containsKey(outChannel) && ParamUtil.isEmpty(businessNo)) {
            return R.error("业务单号不能为空！");
        }
        if (ParamUtil.isEmpty(merchNo) || ParamUtil.isEmpty(orderNo)) {
            return R.error("参数不能为空！");
        }

        return payService.syncOrderAcp(merchNo, orderNo, businessNo);
    }

    /**
     * @param model
     * @return
     * @Description 提现跳转
     */
    @RequiresPermissions("pay:withdraw")
    @GetMapping("/withdraw")
    public ModelAndView withdraw(Model model) {
        UserDO user = ShiroUtils.getUser();
        System.out.println(user.getUserType());
        if (UserType.merch.id() != user.getUserType() && UserType.agent.id() != user.getUserType() && UserType.subAgent.id() != user.getUserType()) {
            model.addAttribute("msg", "目前只支持商户或代理提现");
            return new ModelAndView(PayConstants.url_pay_error_frame);
        }

        this.buildWithdrawParam(model, user.getUsername(), user.getUserType());
        return new ModelAndView(PayConstants.url_pay_withdraw);
    }

    /**
     * @param model
     * @param username
     * @param userType
     * @Description 组装提现页面参数
     */
    private void buildWithdrawParam(Model model, String username, Integer userType) {
        //商户号
        model.addAttribute("username", username);
        PayAcctBal payAcctBal = null;
        if (UserType.merch.id() == userType) {
            payAcctBal = RedisUtil.getMerchBal(username);
//			Merchant merchant = merchantService.getById(username);
//			model.addAttribute("merObj",merchant);
        } else if (UserType.user.id() == userType) {
            payAcctBal = RedisUtil.getPayFoundBal();
        } else if (UserType.agent.id() == userType || UserType.subAgent.id() == userType) {
            payAcctBal = RedisUtil.getAgentBal(username);
//			Agent agent = agentService.get(username);
//			model.addAttribute("merObj",agentService.getById(agent.getAgentId()));
        }
        //资金余额
        model.addAttribute("payAcctBal", payAcctBal);
        //用户卡列表信息
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("username", username);
        List<UserBankDO> userBanks = userBankService.list(map);
        model.addAttribute("userBanks", userBanks);
        //所有的省信息
        model.addAttribute("provinces", locationService.listProvinces());
        //银行代码选择
        model.addAttribute("bankCodes", BankCode.desc());
        //银行卡类型
        model.addAttribute("cardTypes", CardType.desc());

    }

    /**
     * @param order
     * @return
     * @Description 提现确认
     */
    @PostMapping("/withdraw/confirm")
    @RequiresPermissions("pay:withdraw")
    public Object withdraw(@RequestParam("fundPassword") String fundPassword, Order order) {
        UserDO user = ShiroUtils.getUser();
        if (UserType.merch.id() != user.getUserType() && UserType.agent.id() != user.getUserType() && UserType.subAgent.id() != user.getUserType()) {
            return R.error("目前只支持商户或代理提现");
        }
        if (UserType.merch.id() == user.getUserType()) {
            Merchant merchant = merchantService.get(user.getUsername());
            if (!merchant.getStatus().equals(YesNoType.yes.id())) {
                return R.error("您的提现状态被禁用!");
            }
        }
        if (UserType.agent.id() == user.getUserType() || UserType.subAgent.id() == user.getUserType()) {
            Agent agent = agentService.get(user.getUsername());
            if (!agent.getStatus().equals(YesNoType.yes.id())) {
                return R.error("您的状态被禁用!");
            }
        }
        //验证资金密码
        R r = PasswordCheckUtils.checkFundPassword(fundPassword);
        if (R.ifError(r)) {
            return r;
        }
        order.setMerchNo(user.getUsername());
        order.setUserType(user.getUserType());
        return payService.withdraw(order);
    }

    /**
     * @param context
     * @return
     * @Description 跳转动态表单提交
     */
    @GetMapping("/order/jump")
    public ModelAndView jump(@RequestParam(PayConstants.web_context) String context, Model model) {
        logger.info(PayConstants.web_context + context);
        if (ParamUtil.isNotEmpty(context)) {
            try {
                context = new String(RSAUtil.decryptByPrivateKey(Base64Utils.decode(context), QhPayUtil.getQhPrivateKey()));
            } catch (Exception e) {
                model.addAttribute(Constant.result_msg, "解密异常！");
                return new ModelAndView(PayConstants.url_pay_error);
            }
            JSONObject jo = JSONObject.parseObject(context);
            String merchNo = jo.getString(OrderParamKey.merchNo.name());
            String orderNo = jo.getString(OrderParamKey.orderNo.name());
            if (ParamUtil.isEmpty(merchNo) || ParamUtil.isEmpty(orderNo)) {
                model.addAttribute(Constant.result_msg, "订单号或者商户号为空！");
                return new ModelAndView(PayConstants.url_pay_error);
            }
            Order order = RedisUtil.getOrder(merchNo, orderNo);
            if (order == null) {
                model.addAttribute(Constant.result_msg, "订单不存在！");
                return new ModelAndView(PayConstants.url_pay_error);
            }
            model.addAttribute(PayConstants.web_jumpData, order.getJumpData());
            return new ModelAndView(PayConstants.url_pay_jump);
        }
        model.addAttribute(Constant.result_msg, "请勿频繁测试！");
        return new ModelAndView(PayConstants.url_pay_error);
    }
}